package org.example.chapter1;

import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 第一章 1.3 线程通知与等待
 * 本节涉及到的方法：
 * 1、wait()：
 *  API：obj.wait();
 *  约束：调用前需要先获取对象的锁（monitor）
 *  作用：使当前线程进入阻塞挂起状态
 * 2、notify()
 * 3、notifyAll()
 * 4、join()
 * 5、sleep：
 *  API：Thread.sleep(long millis);
 *  作用：使当前线程暂停执行指定时长；期间不会释放拥有的锁
 *
 * 例子：生产者和消费者
 * 线程A负责生产，往队列放数据，队列满了就挂起，有空位就继续放；
 * 线程B负责消费，从队列取数据，队列空了就挂起，有数据就继续取；
 */
public class S13_ThreadWaitAndNotify {

    private final int MAX_SIZE = 10;
    private final Queue<String> queue = new LinkedList<>();
    private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        S13_ThreadWaitAndNotify instance = new S13_ThreadWaitAndNotify();
        instance.launchProducer();
        instance.launchConsumer();
        Object obj = new Object();
        obj.notifyAll();
    }

    public void launchProducer() {
        Thread producer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (queue) {
                        if (queue.size() >= MAX_SIZE) {
                            System.out.println("队列已满，等待消费");

                            // ① 挂起线程
                            try {
                                queue.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            // ② 直接返回
//                            continue;
                        } else {
                            String data = formatter.format(new Date());
                            System.out.println("放入数据：" + data);
                            queue.add(data);
                            queue.notifyAll();
                        }
                    }
                    try {
                        Thread.sleep(2000L); // 模拟生产操作后休息2s
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }


                }
            }
        });
        producer.start();
    }

    public void launchConsumer() {
        Thread consumer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (queue) {
                        if (queue.isEmpty()) {
                            System.out.println("队列已空，等待生产");
                            try {
                                queue.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            String data = queue.poll();
                            System.out.println("取出数据：" + data);
                            queue.notifyAll();
                        }
                    }
                    try {
                        Thread.sleep(2000L); // 模拟消费操作后休息2s
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        consumer.start();
    }


}
